//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include <iostream>
#include <fstream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include <curl/curl.h>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGHTINLINE     10000
#define URLTOPMATCH      "http://topmatch.services.came.sbg.ac.at/topmatch.php?query=%s&target=%s\0"
#define URLTOPMATCHFILE  "http://topmatch.services.came.sbg.ac.at/topmatch.php?queryfile=%s&targetfile=%s\0"
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
static char   errorBuffer[CURL_ERROR_SIZE];
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
static int writer(char *data, size_t size, size_t nmemb, string *buffer) {
  int result = 0;
  if (buffer != NULL) {
    buffer->append(data, size * nmemb);
    result = size * nmemb;
  }
  return result; 
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
string EraseHTMLTAG(string text) {

  size_t  foundB, foundE;

  do {
    foundB = text.find("<");             if (foundB == string::npos) break;
    foundE = text.find(">", foundB + 1); if (foundE == string::npos) break;
    text.erase(int(foundB), int(foundE));
  } while (true);

  return text;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
char* SplitColumn(char* buffer, int position, const char* characters) {

  if (!buffer || !characters || (position <= 0)) return NULL;

  char *part = strtok(buffer, characters);
  if (position == 1) return part;

  int tmpPosition = 1;
  do {
    part = strtok(NULL, characters);
    tmpPosition++;
  } while (part && (tmpPosition != position));

  return part;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
int main (int argc, char** argv) {

  char* nameTargetFile;
  char* nameQueryFile;
  char* nameOutFile;

  if (argc < 4) {
    cout << "Error in the input parameters! Must by like: " << endl;
    cout << "./TopMatchComputeFile <Name Query File> <Name Target File> <Output File>" << endl;
    return 0;
  }
  else {
    cout << "---------------------------------------------------------------------------------" << endl;
    cout << "  Query File : " << argv[1] << endl;
    cout << " Target File : " << argv[2] << endl;
    cout << " Output File : " << argv[3] << endl;
    cout << "---------------------------------------------------------------------------------" << endl;
    nameQueryFile  = new char(strlen(argv[1]) + 1);
    nameTargetFile = new char(strlen(argv[2]) + 1);
    nameOutFile    = new char(strlen(argv[3]) + 1);
    strcpy(nameQueryFile,  argv[1]);
    strcpy(nameTargetFile, argv[2]);
    strcpy(nameOutFile,    argv[3]);
  }

  fstream  fileOut;
  fileOut.open(nameOutFile, fstream::out);
  if (!fileOut.is_open()) {
    if (nameQueryFile)  delete[] nameQueryFile;
    if (nameTargetFile) delete[] nameTargetFile;
    if (nameOutFile)    delete[] nameOutFile;
    return 0;
  }

  cout << "S" << endl;
  cout << "  Number of residue pairs that are structurally equivalent" << endl;
  cout << "  (= length of the alignment, similarity)" << endl;
  cout << "s" << endl;
  cout << "  Relative similarity, expressed in percent" << endl;
  cout << "  (= 100 x (2 x S/( Lq+Lt)), where Lq and Lt are the lengths of the query and target sequences, respectively)" << endl;
  cout << "cq" << endl;
  cout << "  Relative cover of the query with respect to the target, expressed in percent" << endl;
  cout << "  (= 100 x S/Lq)" << endl;
  cout << "ct" << endl;
  cout << "  Relative cover of the target with respect to the query, expressed in percent" << endl;
  cout << "  (= 100 x S/Lt)" << endl;
  cout << "RMS" << endl;
  cout << "  Root-mean-square error of superposition in Ångströms, calculated using all structurally equivalent C-alpha atoms." << endl;
  cout << "Identity" << endl;
  cout << "  Sequence identity of query and target in the equivalent regions, expressed in percent." << endl;

  for (int i = 0; i < 114; i++) { fileOut << "-"; cout << "-"; }
  fileOut << endl; cout << endl;

  fileOut.width(20); fileOut.right; fileOut << " Target |";
  fileOut.width(20); fileOut.right; fileOut << " Query  |";
  fileOut.width(10); fileOut.right; fileOut << "  Rank |";
  fileOut.width(10); fileOut.right; fileOut << "     S |";
  fileOut.width(10); fileOut.right; fileOut << "     s |";
  fileOut.width(10); fileOut.right; fileOut << "    cq |";
  fileOut.width(10); fileOut.right; fileOut << "    ct |";
  fileOut.width(10); fileOut.right; fileOut << "   RMS |";
  fileOut.width(14); fileOut.right; fileOut << " Identity |";
  fileOut << endl;

  cout.width(20); cout.right; cout << " Target |";
  cout.width(20); cout.right; cout << " Query  |";
  cout.width(10); cout.right; cout << "  Rank |";
  cout.width(10); cout.right; cout << "     S |";
  cout.width(10); cout.right; cout << "     s |";
  cout.width(10); cout.right; cout << "    cq |";
  cout.width(10); cout.right; cout << "    ct |";
  cout.width(10); cout.right; cout << "   RMS |";
  cout.width(14); cout.right; cout << " Identity |";
  cout << endl;

  for (int i = 0; i < 114; i++) { fileOut << "-"; cout << "-"; }
  fileOut << endl; cout << endl;

  char   buffer[LENGHTINLINE + 1], buffer1[LENGHTINLINE + 1];

  if (strlen(nameTargetFile) && strlen(nameQueryFile)) {

    char      url[1000];

    CURL*     curl;
    CURLcode  result;

    string    bufferURL;

    sprintf(url, URLTOPMATCHFILE, nameTargetFile, nameQueryFile);
    cout    << "Retrieving " << url << endl;

    curl = curl_easy_init();

    if (curl) {

      curl_easy_setopt(curl, CURLOPT_ERRORBUFFER,      errorBuffer);
      curl_easy_setopt(curl, CURLOPT_URL,              url);
      curl_easy_setopt(curl, CURLOPT_HEADER,           0);
      curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION,   1);
      curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION,    writer);
      curl_easy_setopt(curl, CURLOPT_WRITEDATA,       &bufferURL);

      result = curl_easy_perform(curl);
      curl_easy_cleanup(curl);

      if (result == CURLE_OK) {

        fileOut.width(18); fileOut.right; fileOut << nameTargetFile << " |";
        fileOut.width(18); fileOut.right; fileOut << nameQueryFile  << " |";

        cout.width(18); cout.right; cout << nameTargetFile << " |";
        cout.width(18); cout.right; cout << nameQueryFile  << " |";

        size_t  foundTV, foundRank, found, foundA;
        string  str;

        strcpy(buffer1, target);
        char* targetId = SplitColumn(buffer1, 1, " ,");
        strcpy(buffer1, query);
        char* queryId  = SplitColumn(buffer1, 1, " ,");

        str = "Rank";      foundRank = bufferURL.find(str);
        str = targetId;    foundTV   = bufferURL.find(str, foundRank + 1);
          str = ">";         found     = bufferURL.find(str, foundTV   + 1);
          str = "</a></td>"; foundA    = bufferURL.find(str, found     + 1);

          string rank = bufferURL.substr(found + 1, foundA - found - 1);

//        S
//            Number of residue pairs that are structurally equivalent
//            (= length of the alignment, similarity)
//        s̄
//            Relative similarity, expressed in percent
//            (= 100 x (2 x S/( Lq+Lt)), where Lq and Lt are the lengths of the query and target sequences, respectively)
//        cq
//            Relative cover of the query with respect to the target, expressed in percent
//            (= 100 x S/Lq)
//        ct
//            Relative cover of the target with respect to the query, expressed in percent
//            (= 100 x S/Lt)
//        RMS
//            Root-mean-square error of superposition in Ångströms, calculated using all structurally equivalent C-alpha atoms.
//        Identity
//            Sequence identity of query and target in the equivalent regions, expressed in percent.
//

          str = "<td align=\"right\">"; found  = bufferURL.find(str, foundA + 1);
          str = "</td>";                foundA = bufferURL.find(str, found  + 1);
          
          string S = bufferURL.substr(found + strlen("<td align=\"right\">"), foundA - found - strlen("<td align=\"right\">"));

          str = "<td align=\"right\">"; found  = bufferURL.find(str, foundA + 1);
          str = "</td>";                foundA = bufferURL.find(str, found  + 1);

          string s = bufferURL.substr(found + strlen("<td align=\"right\">"), foundA - found - strlen("<td align=\"right\">"));

          str = "<td align=\"right\">"; found  = bufferURL.find(str, foundA + 1);
          str = "</td>";                foundA = bufferURL.find(str, found  + 1);

          string cq = bufferURL.substr(found + strlen("<td align=\"right\">"), foundA - found - strlen("<td align=\"right\">"));

          str = "<td align=\"right\">"; found  = bufferURL.find(str, foundA + 1);
          str = "</td>";                foundA = bufferURL.find(str, found  + 1);

          string ct = bufferURL.substr(found + strlen("<td align=\"right\">"), foundA - found - strlen("<td align=\"right\">"));

          str = "<td align=\"right\">"; found  = bufferURL.find(str, foundA + 1);
          str = "</td>";                foundA = bufferURL.find(str, found  + 1);

          string RMS = bufferURL.substr(found + strlen("<td align=\"right\">"), foundA - found - strlen("<td align=\"right\">"));

          str = "<td align=\"right\">"; found  = bufferURL.find(str, foundA + 1);
          str = "</td>";                foundA = bufferURL.find(str, found  + 1);

          string identity = bufferURL.substr(found + strlen("<td align=\"right\">"), foundA - found - strlen("<td align=\"right\">"));

          fileOut.width(8);  fileOut.right; fileOut << rank     << " |";
          fileOut.width(8);  fileOut.right; fileOut << S        << " |";
          fileOut.width(8);  fileOut.right; fileOut << s        << " |";
          fileOut.width(8);  fileOut.right; fileOut << cq       << " |";
          fileOut.width(8);  fileOut.right; fileOut << ct       << " |";
          fileOut.width(8);  fileOut.right; fileOut << RMS      << " |";
          fileOut.width(12); fileOut.right; fileOut << identity << " |";
          fileOut << endl;

          cout.width(8);  cout.right; cout << rank     << " |";
          cout.width(8);  cout.right; cout << S        << " |";
          cout.width(8);  cout.right; cout << s        << " |";
          cout.width(8);  cout.right; cout << cq       << " |";
          cout.width(8);  cout.right; cout << ct       << " |";
          cout.width(8);  cout.right; cout << RMS      << " |";
          cout.width(12); cout.right; cout << identity << " |";
          cout << endl;

        }

      }

    }

  }

  for (int i = 0; i < 114; i++) cout << "-";
  cout << endl;

  fileIn.close();
  fileOut.close();

  if (namefileIn)  delete[] namefileIn;
  if (namefileOut) delete[] namefileOut;

  return 1;

}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//


